﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;
using GSync;
using NUnit.Mocks;
using System.IO;

namespace UnitTesting
{
    [TestFixture]
    public class SyncManagerTester
    {

        DynamicMock localStorageMock;
        DynamicMock remoteStorageMock;
        DynamicMock conflictResolver;

        SyncManager mngr;

        [SetUp]
        public void SetUp()
        {
            GSyncFactoryTestingVersion.OverrideInstanceType();
            


            localStorageMock = new DynamicMock( typeof( IDataProvider ) );
            remoteStorageMock = new DynamicMock( typeof( IDataProvider ) );
            conflictResolver = new DynamicMock(typeof(IConflictResolver));

            (GSyncFactory.Instance as GSyncFactoryTestingVersion).localStorageMock = localStorageMock;
            (GSyncFactory.Instance as GSyncFactoryTestingVersion).remoteStorageMock = remoteStorageMock;
            (GSyncFactory.Instance as GSyncFactoryTestingVersion).conflictResolverMock = conflictResolver;
            
            mngr = GSyncFactory.Instance.BuildContactsSyncManager();
        }

        [TearDown]
        public void TearDown()
        {
            //mngr.Dispose();
        }

        [Test]
        public void CopyLocalToRemote()
        {
            GSyncFactory.Instance.GetHashCodesCache().Clear();
            //GSyncFactory.Instance.GetHashCodesCache()[0]

            InternalContact localEntry = new InternalContact();
            localEntry.CanSynchronize = true;
            localEntry.EMails.AddRange(new string[] { "mail1", "mail2", "mail3" });
            localEntry.IMs.AddRange(new string[] { "im1", "im2" });
            localEntry.PhoneNumbers.AddRange(new string[] { "phone1", "phone2", "phone3" });
            localEntry.ID = "123";
            localEntry.Name = "qwer";
            localEntry.Notes = @"a;lsdfa\r\nw34958ergisdhfjk\r\nsd98w453e9r";
            localEntry.Processed = false;



            // local storage behavior
            localStorageMock.ExpectAndReturn("get_CanModifyEntryID", true);
            localStorageMock.ExpectAndReturn("get_AllRecords", (new List<InternalEntry>(new InternalEntry[] { localEntry })).AsReadOnly());
            localStorageMock.Expect("UpdateEntry", localEntry);
            //localStorageMock.Expect("Dispose");


            // remote storage behavior
            remoteStorageMock.ExpectAndReturn("get_CanModifyEntryID", false);
            remoteStorageMock.ExpectAndReturn("get_AllRecords", (new List<InternalEntry>().AsReadOnly()));
            remoteStorageMock.ExpectAndReturn("get_CanModifyEntryID", false);
            remoteStorageMock.Expect("AddEntry", localEntry);
            //remoteStorageMock.Expect("Dispose");


            // conflict resolver behavior
            conflictResolver.ExpectNoCall("ResolveConflict");


            mngr.Synchronize();

            localStorageMock.Verify();
            remoteStorageMock.Verify();
            conflictResolver.Verify();

            Assert.IsNotNull(GSyncFactory.Instance.GetHashCodesCache()[localEntry.ID]);
            Assert.AreEqual(GSyncFactory.Instance.GetHashCodesCache()[localEntry.ID].HashCode, localEntry.GetHashCode());


        }


        [Test]
        public void CopyRemoteToLocal()
        {
            GSyncFactory.Instance.GetHashCodesCache().Clear();
            //GSyncFactory.Instance.GetHashCodesCache()[0]

            InternalContact remoteEntry = new InternalContact();
            remoteEntry.CanSynchronize = true;
            remoteEntry.EMails.AddRange(new string[] { "mail1", "mail2", "mail3" });
            remoteEntry.IMs.AddRange(new string[] { "im1", "im2" });
            remoteEntry.PhoneNumbers.AddRange(new string[] { "phone1", "phone2", "phone3" });
            remoteEntry.ID = "123";
            remoteEntry.Name = "qwer";
            remoteEntry.Notes = @"a;lsdfa\r\nw34958ergisdhfjk\r\nsd98w453e9r";
            remoteEntry.Processed = false;



            // local storage behavior
            localStorageMock.ExpectAndReturn("get_CanModifyEntryID", true);
            localStorageMock.ExpectAndReturn("get_AllRecords",(new List<InternalEntry>().AsReadOnly()) );
            localStorageMock.ExpectAndReturn("get_CanModifyEntryID", true);
            localStorageMock.Expect("AddEntry", remoteEntry);
            //localStorageMock.Expect("Dispose");


            // remote storage behavior
            remoteStorageMock.ExpectAndReturn("get_CanModifyEntryID", false);
            remoteStorageMock.ExpectAndReturn("get_AllRecords", (new List<InternalEntry>(new InternalEntry[] { remoteEntry })).AsReadOnly());
            //remoteStorageMock.ExpectAndReturn("get_CanModifyEntryID", false);
            //remoteStorageMock.Expect("AddEntry", remoteEntry);
            //remoteStorageMock.Expect("Dispose");


            // conflict resolver behavior
            conflictResolver.ExpectNoCall("ResolveConflict");


            mngr.Synchronize();

            localStorageMock.Verify();
            remoteStorageMock.Verify();
            conflictResolver.Verify();

            Assert.IsNotNull(GSyncFactory.Instance.GetHashCodesCache()[remoteEntry.ID]);
            Assert.AreEqual(GSyncFactory.Instance.GetHashCodesCache()[remoteEntry.ID].HashCode, remoteEntry.GetHashCode());


        }

        [Test]
        public void UpdateRemoteFromLocal()
        {
            GSyncFactory.Instance.GetHashCodesCache().Clear();
            //GSyncFactory.Instance.GetHashCodesCache()[0]

            InternalContact remoteEntry = new InternalContact();
            remoteEntry.CanSynchronize = true;
            remoteEntry.EMails.AddRange(new string[] { "mail1", "mail2", "mail3" });
            remoteEntry.IMs.AddRange(new string[] { "im1", "im2" });
            remoteEntry.PhoneNumbers.AddRange(new string[] { "phone1", "phone2", "phone3" });
            remoteEntry.ID = "123";
            remoteEntry.Name = "qwer";
            remoteEntry.Notes = @"a;lsdfa\r\nw34958ergisdhfjk\r\nsd98w453e9r";
            remoteEntry.Processed = false;

            InternalContact localEntry = new InternalContact();
            localEntry.CanSynchronize = true;
            localEntry.EMails.AddRange(new string[] { "mail1", "mail2", "sergf" });
            localEntry.IMs.AddRange(new string[] { "im1", "im2", "asdf" });
            localEntry.PhoneNumbers.AddRange(new string[] { "phone2", "phone3" });
            localEntry.ID = "123";
            localEntry.Name = "qwer";
            localEntry.Notes = @"tyuhrf";
            localEntry.Processed = false;

            GSyncFactory.Instance.GetHashCodesCache()[localEntry.ID] = new CacheRecord() 
                                                                        {   ID = remoteEntry.ID,
                                                                            HashCode = remoteEntry.GetHashCode(), 
                                                                            Type = CacheRecord.Contact, 
                                                                            Updated = DateTime.Today };



            // local storage behavior
            localStorageMock.ExpectAndReturn("get_CanModifyEntryID", true);
            localStorageMock.ExpectAndReturn("get_AllRecords", (new List<InternalEntry>(new InternalEntry[] { localEntry })).AsReadOnly());
            
            //localStorageMock.Expect("AddEntry", remoteEntry);
            //localStorageMock.Expect("Dispose");


            // remote storage behavior
            remoteStorageMock.ExpectAndReturn("get_CanModifyEntryID", false);
            remoteStorageMock.ExpectAndReturn("get_AllRecords", (new List<InternalEntry>(new InternalEntry[] { remoteEntry })).AsReadOnly());

            remoteStorageMock.Expect("UpdateEntry", localEntry);
            //remoteStorageMock.Expect("Dispose");


            // conflict resolver behavior
            conflictResolver.ExpectNoCall("ResolveConflict");


            mngr.Synchronize();

            localStorageMock.Verify();
            remoteStorageMock.Verify();
            conflictResolver.Verify();

            Assert.IsNotNull(GSyncFactory.Instance.GetHashCodesCache()[remoteEntry.ID]);
            Assert.AreEqual(GSyncFactory.Instance.GetHashCodesCache()[remoteEntry.ID].HashCode, localEntry.GetHashCode());


        }


        [Test]
        public void UpdateLocalFromRemote()
        {
            GSyncFactory.Instance.GetHashCodesCache().Clear();
            //GSyncFactory.Instance.GetHashCodesCache()[0]

            InternalContact remoteEntry = new InternalContact();
            remoteEntry.CanSynchronize = true;
            remoteEntry.EMails.AddRange(new string[] { "mail1", "mail2", "mail3" });
            remoteEntry.IMs.AddRange(new string[] { "im1", "im2" });
            remoteEntry.PhoneNumbers.AddRange(new string[] { "phone1", "phone2", "phone3" });
            remoteEntry.ID = "123";
            remoteEntry.Name = "qwer";
            remoteEntry.Notes = @"a;lsdfa\r\nw34958ergisdhfjk\r\nsd98w453e9r";
            remoteEntry.Processed = false;

            InternalContact localEntry = new InternalContact();
            localEntry.CanSynchronize = true;
            localEntry.EMails.AddRange(new string[] { "mail1", "mail2", "sergf" });
            localEntry.IMs.AddRange(new string[] { "im1", "im2", "asdf" });
            localEntry.PhoneNumbers.AddRange(new string[] { "phone2", "phone3" });
            localEntry.ID = "123";
            localEntry.Name = "qwer";
            localEntry.Notes = @"tyuhrf";
            localEntry.Processed = false;

            GSyncFactory.Instance.GetHashCodesCache()[localEntry.ID] = new CacheRecord()
            {
                ID = localEntry.ID,
                HashCode = localEntry.GetHashCode(),
                Type = CacheRecord.Contact,
                Updated = DateTime.Today
            };



            // local storage behavior
            localStorageMock.ExpectAndReturn("get_CanModifyEntryID", true);
            localStorageMock.ExpectAndReturn("get_AllRecords", (new List<InternalEntry>(new InternalEntry[] { localEntry })).AsReadOnly());

            localStorageMock.Expect("UpdateEntry", remoteEntry);
            //localStorageMock.Expect("Dispose");


            // remote storage behavior
            remoteStorageMock.ExpectAndReturn("get_CanModifyEntryID", false);
            remoteStorageMock.ExpectAndReturn("get_AllRecords", (new List<InternalEntry>(new InternalEntry[] { remoteEntry })).AsReadOnly());

            //remoteStorageMock.Expect("UpdateEntry", localEntry);
            //remoteStorageMock.Expect("Dispose");


            // conflict resolver behavior
            conflictResolver.ExpectNoCall("ResolveConflict");


            mngr.Synchronize();

            localStorageMock.Verify();
            remoteStorageMock.Verify();
            conflictResolver.Verify();

            Assert.IsNotNull(GSyncFactory.Instance.GetHashCodesCache()[remoteEntry.ID]);
            Assert.AreEqual(GSyncFactory.Instance.GetHashCodesCache()[remoteEntry.ID].HashCode, remoteEntry.GetHashCode());


        }

        [Test]
        public void UpdateRemoteFromLocalResolveConflict()
        {
            GSyncFactory.Instance.GetHashCodesCache().Clear();
            //GSyncFactory.Instance.GetHashCodesCache()[0]

            InternalContact remoteEntry = new InternalContact();
            remoteEntry.CanSynchronize = true;
            remoteEntry.EMails.AddRange(new string[] { "mail1", "mail2", "mail3" });
            remoteEntry.IMs.AddRange(new string[] { "im1", "im2" });
            remoteEntry.PhoneNumbers.AddRange(new string[] { "phone1", "phone2", "phone3" });
            remoteEntry.ID = "123";
            remoteEntry.Name = "qwer";
            remoteEntry.Notes = @"a;lsdfa\r\nw34958ergisdhfjk\r\nsd98w453e9r";
            remoteEntry.Processed = false;

            InternalContact localEntry = new InternalContact();
            localEntry.CanSynchronize = true;
            localEntry.EMails.AddRange(new string[] { "mail1", "mail2", "sergf" });
            localEntry.IMs.AddRange(new string[] { "im1", "im2", "asdf" });
            localEntry.PhoneNumbers.AddRange(new string[] { "phone2", "phone3" });
            localEntry.ID = "123";
            localEntry.Name = "qwer";
            localEntry.Notes = @"tyuhrf";
            localEntry.Processed = false;

            GSyncFactory.Instance.GetHashCodesCache()[remoteEntry.ID] = new CacheRecord()
            {
                ID = remoteEntry.ID,
                HashCode = 123456,
                Type = CacheRecord.Contact,
                Updated = DateTime.Today
            };



            // local storage behavior
            localStorageMock.ExpectAndReturn("get_CanModifyEntryID", true);
            localStorageMock.ExpectAndReturn("get_AllRecords", (new List<InternalEntry>(new InternalEntry[] { localEntry })).AsReadOnly());

            //localStorageMock.Expect("UpdateEntry", remoteEntry);
            //localStorageMock.Expect("Dispose");


            // remote storage behavior
            remoteStorageMock.ExpectAndReturn("get_CanModifyEntryID", false);
            remoteStorageMock.ExpectAndReturn("get_AllRecords", (new List<InternalEntry>(new InternalEntry[] { remoteEntry })).AsReadOnly());

            remoteStorageMock.Expect("UpdateEntry", localEntry);
            //remoteStorageMock.Expect("Dispose");


            // conflict resolver behavior
            conflictResolver.Expect("set_LocalEntry", localEntry);
            conflictResolver.Expect("set_RemoteEntry", remoteEntry);
            conflictResolver.ExpectAndReturn("ResolveConflict", UpdatePolicy.UseLocalData);


            mngr.Synchronize();

            localStorageMock.Verify();
            remoteStorageMock.Verify();
            conflictResolver.Verify();


            Assert.IsNotNull(GSyncFactory.Instance.GetHashCodesCache()[remoteEntry.ID]);
            Assert.AreEqual(GSyncFactory.Instance.GetHashCodesCache()[remoteEntry.ID].HashCode, localEntry.GetHashCode());


        }


        [Test]
        public void UpdateLocalFromRemoteResolveConflict()
        {
            GSyncFactory.Instance.GetHashCodesCache().Clear();
            //GSyncFactory.Instance.GetHashCodesCache()[0]

            InternalContact remoteEntry = new InternalContact();
            remoteEntry.CanSynchronize = true;
            remoteEntry.EMails.AddRange(new string[] { "mail1", "mail2", "mail3" });
            remoteEntry.IMs.AddRange(new string[] { "im1", "im2" });
            remoteEntry.PhoneNumbers.AddRange(new string[] { "phone1", "phone2", "phone3" });
            remoteEntry.ID = "123";
            remoteEntry.Name = "qwer";
            remoteEntry.Notes = @"a;lsdfa\r\nw34958ergisdhfjk\r\nsd98w453e9r";
            remoteEntry.Processed = false;

            InternalContact localEntry = new InternalContact();
            localEntry.CanSynchronize = true;
            localEntry.EMails.AddRange(new string[] { "mail1", "mail2", "sergf" });
            localEntry.IMs.AddRange(new string[] { "im1", "im2", "asdf" });
            localEntry.PhoneNumbers.AddRange(new string[] { "phone2", "phone3" });
            localEntry.ID = "123";
            localEntry.Name = "qwer";
            localEntry.Notes = @"tyuhrf";
            localEntry.Processed = false;

            GSyncFactory.Instance.GetHashCodesCache()[remoteEntry.ID] = new CacheRecord()
            {
                ID = remoteEntry.ID,
                HashCode = 123456,
                Type = CacheRecord.Contact,
                Updated = DateTime.Today
            };



            // local storage behavior
            localStorageMock.ExpectAndReturn("get_CanModifyEntryID", true);
            localStorageMock.ExpectAndReturn("get_AllRecords", (new List<InternalEntry>(new InternalEntry[] { localEntry })).AsReadOnly());

            localStorageMock.Expect("UpdateEntry", remoteEntry);
            //localStorageMock.Expect("Dispose");


            // remote storage behavior
            remoteStorageMock.ExpectAndReturn("get_CanModifyEntryID", false);
            remoteStorageMock.ExpectAndReturn("get_AllRecords", (new List<InternalEntry>(new InternalEntry[] { remoteEntry })).AsReadOnly());

            //remoteStorageMock.Expect("UpdateEntry", localEntry);
            //remoteStorageMock.Expect("Dispose");


            // conflict resolver behavior
            conflictResolver.Expect("set_LocalEntry", localEntry);
            conflictResolver.Expect("set_RemoteEntry", remoteEntry);
            conflictResolver.ExpectAndReturn("ResolveConflict", UpdatePolicy.UseServerData);

            
            mngr.Synchronize();

            localStorageMock.Verify();
            remoteStorageMock.Verify();
            conflictResolver.Verify();


            Assert.IsNotNull(GSyncFactory.Instance.GetHashCodesCache()[remoteEntry.ID]);
            Assert.AreEqual(GSyncFactory.Instance.GetHashCodesCache()[remoteEntry.ID].HashCode, remoteEntry.GetHashCode());


        }

        [Test]
        public void NoUpdateResolveConflict()
        {
            GSyncFactory.Instance.GetHashCodesCache().Clear();
            //GSyncFactory.Instance.GetHashCodesCache()[0]

            InternalContact remoteEntry = new InternalContact();
            remoteEntry.CanSynchronize = true;
            remoteEntry.EMails.AddRange(new string[] { "mail1", "mail2", "mail3" });
            remoteEntry.IMs.AddRange(new string[] { "im1", "im2" });
            remoteEntry.PhoneNumbers.AddRange(new string[] { "phone1", "phone2", "phone3" });
            remoteEntry.ID = "123";
            remoteEntry.Name = "qwer";
            remoteEntry.Notes = @"a;lsdfa\r\nw34958ergisdhfjk\r\nsd98w453e9r";
            remoteEntry.Processed = false;

            InternalContact localEntry = new InternalContact();
            localEntry.CanSynchronize = true;
            localEntry.EMails.AddRange(new string[] { "mail1", "mail2", "sergf" });
            localEntry.IMs.AddRange(new string[] { "im1", "im2", "asdf" });
            localEntry.PhoneNumbers.AddRange(new string[] { "phone2", "phone3" });
            localEntry.ID = "123";
            localEntry.Name = "qwer";
            localEntry.Notes = @"tyuhrf";
            localEntry.Processed = false;

            GSyncFactory.Instance.GetHashCodesCache()[remoteEntry.ID] = new CacheRecord()
            {
                ID = remoteEntry.ID,
                HashCode = 123456,
                Type = CacheRecord.Contact,
                Updated = DateTime.Today
            };



            // local storage behavior
            localStorageMock.ExpectAndReturn("get_CanModifyEntryID", true);
            localStorageMock.ExpectAndReturn("get_AllRecords", (new List<InternalEntry>(new InternalEntry[] { localEntry })).AsReadOnly());

            localStorageMock.ExpectNoCall("UpdateEntry");
            //localStorageMock.Expect("Dispose");


            // remote storage behavior
            remoteStorageMock.ExpectAndReturn("get_CanModifyEntryID", false);
            remoteStorageMock.ExpectAndReturn("get_AllRecords", (new List<InternalEntry>(new InternalEntry[] { remoteEntry })).AsReadOnly());

            remoteStorageMock.ExpectNoCall("UpdateEntry");
            //remoteStorageMock.Expect("Dispose");


            // conflict resolver behavior
            conflictResolver.Expect("set_LocalEntry", localEntry);
            conflictResolver.Expect("set_RemoteEntry", remoteEntry);
            conflictResolver.ExpectAndReturn("ResolveConflict", UpdatePolicy.Cancel);


            mngr.Synchronize();

            localStorageMock.Verify();
            remoteStorageMock.Verify();
            conflictResolver.Verify();


            Assert.IsNotNull(GSyncFactory.Instance.GetHashCodesCache()[remoteEntry.ID]);
            Assert.AreEqual(GSyncFactory.Instance.GetHashCodesCache()[remoteEntry.ID].HashCode, 123456);


        }
    }



}
